using System.Collections.Generic;
using Gameplay.PVE.Config;
using Gameplay.PVE.Entity;
using Gameplay.PVE.Skill;
using Gameplay.PVE.Utils;
using UnityEngine;
using Yoozoo.Libs;
using Yoozoo.Managers;

namespace Gameplay.PVE
{
    public class ElementSystem : IClass
    {
        private List<ElementBase> elementList;
        private Dictionary<int, int> elementCount;

        /// <summary>
        /// 外部触发的事件，需要检查元素是否需要因此销毁
        /// </summary>
        /// <param name="triggerType"></param>
        public void Trigger(int triggerType)
        {
            for (int i = 0; i < elementList.Count; i++)
            {
                elementList[i].CheckNeedDestroyByTrigger(triggerType);
            }
        }

        public void OnSkillEnd(SkillBase skill)
        {
            for (int i = 0; i < elementList.Count; i++)
            {
                var element = elementList[i];
                if (element.isSkillAdditive && element.skill == skill)
                {
                    element.IsFree = true;
                }
            }
        }

        public void Pause()
        {
            for (int i = 0; i < elementList.Count; i++)
            {
                elementList[i].Pause();
            }
        }

        public void Resume()
        {
            for (int i = 0; i < elementList.Count; i++)
            {
                elementList[i].Resume();
            }
        }
        
        void IClass.OnReset()
        {
            if (elementList != null)
            {
                for (int i = 0; i < elementList.Count; i++)
                {
                    elementList[i].Free();
                    ClassManager.Free(elementList[i]);
                }
                elementList.Clear();
            }
            elementCount?.Clear();
        }

        public void Initialize()
        {
            elementList = new List<ElementBase>();
            elementCount = new Dictionary<int, int>();
        }

        public void Update()
        {
            for (int i = 0; i < elementList.Count; i++)
            {
                elementList[i].Update();
            }
            
            for (int i = 0; i < elementList.Count; i++)
            {
                if (elementList[i].IsFree)
                {
                    if (elementCount.TryGetValue(elementList[i].config.id, out var count))
                    {
                        elementCount[elementList[i].config.id] = count - 1;
                    }
                    elementList[i].Free();
                    ClassManager.Free(elementList[i]);
                    elementList.RemoveAt(i);
                    i--;
                }
            }
        }

        public void RemoveElement(int removeType)
        {
            for (int i = 0; i < elementList.Count; i++)
            {
                if ((elementList[i].config.buff_type & removeType) > 0)
                {
                    if (elementCount.TryGetValue(elementList[i].config.id, out var count))
                    {
                        elementCount[elementList[i].config.id] = count - 1;
                    }
                    elementList[i].Free();
                    ClassManager.Free(elementList[i]);
                    elementList.RemoveAt(i);
                    i--;
                }
            }
        }

        public void OnDead()
        {
            for (int i = 0; i < elementList.Count; i++)
            {
                elementList[i].Free();
                ClassManager.Free(elementList[i]);
            }
            elementList.Clear();
        }
        
        public ElementBase AddElement(int id, UnitBase target, UnitBase source, PveSkillElementConfig config,Vector3 bulletPosition, bool isCrit,float rigidBreak,SkillBase skill,bool isSkillAdditive)
        {
            if (config == null)
            {
                return null;
            }

            if (target.Data.isDead && (config.element_type == 1 || config.element_type == 4))
            {
                return null;
            }
            
            if (target.Data.invulnerable && source.Data.team != target.Data.team)//无敌时无视敌方的子弹
            {
                var d = target.Data;
                PveFlyTextManager.Instance.ShowImmuneFlyText(d.flyTextCriticalPosition, d.id, d.team);
                return null;
            }
            
            if (elementList.Count > 500)
            {
                Debug.Log("元素列表过长，怀疑子元素嵌套 "+config.id);
                return null;
            }
            
            if (config.element_type == 4 && !target.Data.controlable)
            {
                if (config.buff_type != 12)
                {
                    var d = target.Data;
                    PveFlyTextManager.Instance.ShowImmuneFlyText(d.flyTextCriticalPosition, d.id, d.team);
                }
                return null;
            }
            ElementBase element = null;

            
            //判断是否叠到了最大层数
            /*if (config.combine_max > 0)
            {
                if (elementCount.TryGetValue(config.id, out var count) && count >= config.combine_max)
                {
                    return null;
                }
            }*/
            //if (config.buff_type != 0)
            {
                //判断是否冲突
                for (int i = 0; i < elementList.Count; i++)
                {
                    var existElement = elementList[i];
                    if (config.buff_type != 0)
                    {
                        var existType = existElement.GetExistType(config);
                        if (existType == EElementExistType.Filter)
                        {
                            return null;
                        }
                        if (existType == EElementExistType.Cover)
                        {
                            element = existElement;
                            element.RefreshTime();
                            return element;
                        }
                    }
                    else
                    {
                        if (config.id == existElement.config.id)
                        {
                            if (config.combine_type == (int)EElementExistType.Filter)
                            {
                                return null;
                            }
                            else if (config.combine_type == (int)EElementExistType.Cover)
                            {
                                element = existElement;
                                element.RefreshTime();
                                return element;
                            }
                        }
                    }

                    //判断共存
                    if (existElement.config.id == config.id &&
                        config.combine_type == (int) EElementExistType.CoexistAndRefresh)
                    {
                        existElement.RefreshTime();
                        element = existElement;
                        
                        if (CheckCanExecute(element.config))
                        {
                            AddToElements(element.config);
                            element.Execute();
                        }
                        return element;
                    }
                }
            }
           
            if (element == null)
            {
                element = GetElementByType(config.element_type);
            }   
            if (element != null)
            {
                element.id = id;
                element.isSkillAdditive = isSkillAdditive;
                element.SetTarget(target,source);
                element.SetSourceSkill(skill);
                element.SetRigidBreak(rigidBreak);
                element.SetBulletPosition(bulletPosition);
                element.Parse(config,isCrit);
                if (CheckCanExecute(element.config))
                {
                    AddToElements(element.config);
                    element.Execute();
                }
                
                elementList.Add(element);
                //判断是否有子元素
                for (int i = 0; i < config.sub_elements.Count; i++)
                {
                    var subConfig = PveUtils.GetSkillElementConfig(config.sub_elements[i]);
                    if (subConfig != null)
                    {
                        element.AddSubElements(AddElement(id, target, source, subConfig, bulletPosition, isCrit,
                            rigidBreak, skill,isSkillAdditive));
                    }
                }
            }

            return element;
        }

        private bool CheckCanExecute(PveSkillElementConfig config)
        {
            if (config.combine_max > 0)
            {
                if (elementCount.TryGetValue(config.id, out var count) && count >= config.combine_max)
                {
                    return false;
                }
            }
            return true;
        }

        private void AddToElements(PveSkillElementConfig config)
        {
            if (!elementCount.TryGetValue(config.id,out var count))
            {
                elementCount.Add(config.id,1);
            }
            else
            {
                elementCount[config.id] = count + 1;
            }
        }

        public void CheckTrigger(ElementBase element)
        {
            for (int i = 0; i < elementList.Count; i++)
            {
                if (elementList[i] is TriggerElement triggerElement && !triggerElement.IsFree)
                {
                    triggerElement.CheckTrigger(element);
                }
            }
        }
        
        private ElementBase GetElementByType(int type)
        {
            ElementBase element = null;
            if (type == 1)
            {
                element = ClassManager.Get<DamageElement>();
            }
            else if (type == 2)
            {
                element = ClassManager.Get<ChangePropertyElement>();
            }
            else if (type == 3)
            {
                element = ClassManager.Get<TriggerElement>();
            }
            else if (type == 4)
            {
                element = ClassManager.Get<ControlElement>();
            }
            else if (type == 5)
            {
                element = ClassManager.Get<ImmuneElement>();
            }
            else if (type == 6)
            {
                element = ClassManager.Get<ShieldElement>();
            }
            return element;
        }
    }
}